#include "TinyJsonWriter.h"
#include "Array.h"
#include "Object.h"
#include <iomanip>
#include <fstream>
#include "Log.h"
namespace tinyjson
{
    void TinyJsonWriter::stringify()
    {
        if (m_value == 0)
            return;
        stringify_value(*m_output, *m_value);
        m_isStringified = true;
    }

    void TinyJsonWriter::stringify_value(std::ostream &output, const TinyJsonValue &value)
    {
        TinyJsonType type = value.get_type();
        switch (type)
        {
        case TinyJsonType::TINY_JSON_NULL:
            output << value.get_null();
            break;
        case TinyJsonType::TINY_JSON_TRUE:
            output << value.get_true();
            break;
        case TinyJsonType::TINY_JSON_FALSE:
            output << value.get_false();
            break;
        case TinyJsonType::TINY_JSON_NUMBER:
            // std::setprecision(17)设置输出浮点数时保留小数点后17位，如果数字小于17位，显示真实的位数(不用在后面填0补齐17位)
            //如果不使用std::setprecision，使用<<输出double，编译器会自动进行位数舍弃
            //例如1.0000000000000002会输出为1
            output << std::setprecision(17) << value.get_number();
            break;
        case TinyJsonType::TINY_JSON_STRING:
            stringify_string(output, value.get_string());
            break;
        case TinyJsonType::TINY_JSON_ARRAY:
            stringify_array(output, value.get_array());
            break;
        case TinyJsonType::TINY_JSON_OBJECT:
            stringify_object(output, value.get_object());
            break;
        default:
            break;
        }
    }

    void TinyJsonWriter::stringify_string(std::ostream &output, const String &src)
    {
        output << "\"";
        for (size_t i = 0; i < src.size(); i++)
        {
            char ch = src[i];
            switch (ch)
            {
            case '\"':
                output << "\\\"";
                break;
            case '\\':
                output << "\\\\";
                break;
            case '\b':
                output << "\\b";
                break;
            case '\f':
                output << "\\f";
                break;
            case '\n':
                output << "\\n";
                break;
            case '\r':
                output << "\\r";
                break;
            case '\t':
                output << "\\t";
                break;
            default:
                output << ch;
                break;
            }
        }
        output << "\"";
    }

    void TinyJsonWriter::stringify_array(std::ostream &output, const Array &array)
    {
        output << '[';
        for (size_t i = 0; i < array.size(); ++i)
        {
            TinyJsonValue &value = *array[i];
            stringify_value(output, value);
            if (i != array.size() - 1)
                output << ',';
        }
        output << ']';
    }

    void TinyJsonWriter::stringify_object(std::ostream &output, const Object &object)
    {
        output << '{';
        auto it = object.begin();
        while (it != object.end())
        {
            const String &key = it->first;
            const TinyJsonValue &value = *it->second;
            stringify_string(output, key);
            output << ":";
            stringify_value(output, value);
            it++;
            if (it != object.end())
                output << ",";
        }
        output << '}';
    }

    void TinyJsonWriter::write(const char *filepath)
    {
        if (!m_isStringified)
            stringify();

        SPDLOG_LOGGER_DEBUG(spdlog::get("spdlog"),"{}",m_output->str());

        std::ofstream file(filepath);
        file << m_output->str();
        file.close();
    }

    String TinyJsonWriter::stringify_result()
    {
        return m_output->str();
    }

    void TinyJsonWriter::push(const TinyJsonValue &val)
    {
        m_value = std::make_shared<TinyJsonValue>(val);
        m_output = std::make_shared<std::ostringstream>();
        m_isStringified = false;
    }
}